package com.ruoyi.biz.service;

import com.ruoyi.biz.domain.BizProject;
import com.ruoyi.biz.domain.BizSector;
import com.ruoyi.biz.enums.ProjectStatusEnum;
import com.ruoyi.biz.mapper.BizInvoiceMapper;
import com.ruoyi.biz.model.dto.StatAuditDto;
import com.ruoyi.biz.model.req.StatReq;
import com.ruoyi.biz.model.resp.BizInvoiceResp;
import com.ruoyi.biz.model.resp.BizProjectResp;
import com.ruoyi.biz.utils.ReqUtils;
import com.ruoyi.biz.utils.StatUtils;
import com.ruoyi.system.service.ISysConfigService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author tianl
 * @date 2025/2/25
 * @description:
 */
@Service
public class StatAuditService {
    @Autowired
    private BizProjectService bizProjectService;
    @Autowired
    private BizInvoiceMapper bizInvoiceMapper;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    private BizSectorService bizSectorService;

    public StatAuditDto initDto(List<BizProjectResp> list) {
        Map<String, List<BizProjectResp>> map = list.stream().collect(Collectors.groupingBy(BizProjectResp::getDeptName));
        List<String> listStr = map.entrySet().stream()
                .map(entry -> entry.getKey() + "：" + entry.getValue().size())
                .collect(Collectors.toList());
        return new StatAuditDto(list.size(), String.join("<br>", listStr));
    }

    public List<StatAuditDto> statAuditNumBar(Integer year) {
        StatReq req = ReqUtils.getReq(year);
        List<StatAuditDto> result = new ArrayList<>();
        String difficultLevel = configService.selectConfigByKey("biz.project.difficult.level");
        if (StringUtils.isBlank(difficultLevel)) {
            difficultLevel = "difficult";
        }
        String auditCode = configService.selectConfigByKey("biz.sector.audit.code");
        if (StringUtils.isBlank(auditCode)) {
            auditCode = "f4d6d387d6f746fab111d243c3fb87a5";
        }
        List<BizProjectResp> projectList = bizProjectService.listStatResp(req);
        if (CollectionUtils.isEmpty(projectList)) {
            return new ArrayList<>();
        }
        BizSector sector = bizSectorService.findByCode(auditCode);
        if (sector == null) {
            return new ArrayList<>();
        }
        List<BizSector> allSectorList = bizSectorService.list();
        List<BizSector> childSectorList = allSectorList.stream()
                .filter(r -> r.getParentId() != 0).collect(Collectors.toList());
        List<BizSector> sectorList = StatUtils.pack(sector.getId(), childSectorList);
        List<Long> sectorIds = sectorList.stream().map(BizSector::getId).collect(Collectors.toList());
        sectorIds.add(sector.getId());
        List<BizProjectResp> tmp = projectList.stream()
                .filter(r -> sectorIds.contains(r.getSectorId())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(tmp)) {
            return new ArrayList<>();
        }
        List<BizProjectResp> warn = tmp.stream()
                .filter(r -> r.getWarn() != null && r.getWarn()).collect(Collectors.toList());
        //第6，预警
        result.add(initDto(warn));
        List<BizProjectResp> due = tmp.stream()
                .filter(r -> r.getProjectStatus() != null)
                .filter(r -> r.getProjectStatus().equals(ProjectStatusEnum.OVERDUE.getCode())).collect(Collectors.toList());
        //第5，超期
        result.add(initDto(due));
        List<BizProjectResp> done = tmp.stream()
                .filter(r -> r.getProjectStatus() != null)
                .filter(r -> r.getProjectStatus().equals(ProjectStatusEnum.DONE.getCode())
                        || r.getProjectStatus().equals(ProjectStatusEnum.DG.getCode())
                ).collect(Collectors.toList());
        //第4，完成
        result.add(initDto(done));
        List<BizProjectResp> doing = tmp.stream()
                .filter(r -> r.getProjectStatus() != null)
                .filter(r -> r.getProjectStatus().equals(ProjectStatusEnum.DOING.getCode())).collect(Collectors.toList());
        //第3，在途
        result.add(initDto(doing));
        String finalDifficultLevel = difficultLevel;
        List<BizProjectResp> difficult = tmp.stream()
                .filter(r -> r.getLevel() != null)
                .filter(r -> r.getLevel().equals(finalDifficultLevel)).collect(Collectors.toList());
        //第2，疑难
        result.add(initDto(difficult));
        //第1，累计
        result.add(initDto(tmp));
        return result;
    }

    public StatAuditDto initAmountDto(BigDecimal amount, List<BizProjectResp> list) {
        Map<String, List<BizProjectResp>> map = list.stream().collect(Collectors.groupingBy(BizProjectResp::getDeptName));
        List<String> listStr = map.entrySet().stream()
                .map(entry -> entry.getKey() + "：" + entry.getValue().size())
                .collect(Collectors.toList());
        return new StatAuditDto(amount, String.join("<br>", listStr));
    }

    public List<StatAuditDto> statAuditAmountBar(Integer year) {
        StatReq req = ReqUtils.getReq(year);
        List<StatAuditDto> result = new ArrayList<>();
        List<BizProjectResp> projectList = bizProjectService.listStatResp(req);
        if (CollectionUtils.isEmpty(projectList)) {
            return new ArrayList<>();
        }
        String auditCode = configService.selectConfigByKey("biz.sector.audit.code");
        if (StringUtils.isBlank(auditCode)) {
            auditCode = "f4d6d387d6f746fab111d243c3fb87a5";
        }
        BizSector sector = bizSectorService.findByCode(auditCode);
        if (sector == null) {
            return new ArrayList<>();
        }
        List<BizSector> allSectorList = bizSectorService.list();
        List<BizSector> childSectorList = allSectorList.stream()
                .filter(r -> r.getParentId() != 0).collect(Collectors.toList());
        List<BizSector> sectorList = StatUtils.pack(sector.getId(), childSectorList);
        List<Long> sectorIds = sectorList.stream().map(BizSector::getId).collect(Collectors.toList());
        sectorIds.add(sector.getId());
        List<BizProjectResp> tmp = projectList.stream()
                .filter(r -> sectorIds.contains(r.getSectorId())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(tmp)) {
            return new ArrayList<>();
        }
        BigDecimal finalProfit = tmp.stream()
                .filter(r -> r.getFinalProfit() != null)
                .map(BizProject::getFinalProfit)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        Map<String, BigDecimal> map6 = tmp.stream()
                .filter(r -> r.getFinalProfit() != null)
                .collect(Collectors.groupingBy(BizProjectResp::getDeptName,
                        Collectors.mapping(BizProjectResp::getFinalProfit,
                                Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
        List<String> list6 = map6.entrySet().stream()
                .map(entry -> entry.getKey() + "：" + entry.getValue())
                .collect(Collectors.toList());
        //第6，最终利润
        result.add(new StatAuditDto(finalProfit, String.join("<br>", list6)));
        BigDecimal baseCost = tmp.stream()
                .filter(r -> r.getBaseCost() != null)
                .map(BizProject::getBaseCost)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        Map<String, BigDecimal> map5 = tmp.stream()
                .filter(r -> r.getBaseCost() != null)
                .collect(Collectors.groupingBy(BizProjectResp::getDeptName,
                        Collectors.mapping(BizProjectResp::getBaseCost,
                                Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
        List<String> list5 = map5.entrySet().stream()
                .map(entry -> entry.getKey() + "：" + entry.getValue())
                .collect(Collectors.toList());
        //第5，成本支出
        result.add(new StatAuditDto(baseCost, String.join("<br>", list5)));
        List<Long> projectIds = tmp.stream().map(BizProject::getId).collect(Collectors.toList());
        List<BizInvoiceResp> invoices = bizInvoiceMapper.listByProjectIds(projectIds);
        if (req.getTimes() != null && req.getTimes().size() >= 2) {
            invoices = invoices.stream()
                    .filter(r -> r.getInvoiceTime().compareTo(req.getTimes().get(0)) >= 0
                            && r.getInvoiceTime().compareTo(req.getTimes().get(1)) <= 0)
                    .collect(Collectors.toList());
        }
        BigDecimal totalAmount = tmp.stream()
                .filter(r -> r.getTotalAmount() != null)
                .map(BizProject::getTotalAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal invoicesAmount = invoices.stream()
                .filter(r -> r.getInvoiceMoney() != null)
                .map(BizInvoiceResp::getInvoiceMoney)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        Map<String, BigDecimal> map4 = tmp.stream()
                .filter(r -> r.getTotalAmount() != null)
                .collect(Collectors.groupingBy(BizProjectResp::getDeptName,
                        Collectors.mapping(BizProjectResp::getTotalAmount,
                                Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
        Map<String, BigDecimal> map3 = invoices.stream()
                .filter(r -> r.getInvoiceMoney() != null)
                .collect(Collectors.groupingBy(BizInvoiceResp::getDeptName,
                        Collectors.mapping(BizInvoiceResp::getInvoiceMoney,
                                Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
        List<String> list4 = map4.entrySet().stream()
                .map(entry -> {
                    if (map3.containsKey(entry.getKey())) {
                        return entry.getKey() + "：" + (entry.getValue().subtract(map3.get(entry.getKey())));
                    } else {
                        return entry.getKey() + "：" + entry.getValue();
                    }

                })
                .collect(Collectors.toList());
        //第4，待开票
        result.add(new StatAuditDto(totalAmount.subtract(invoicesAmount), String.join("<br>", list4)));
        List<String> list3 = map3.entrySet().stream()
                .map(entry -> entry.getKey() + "：" + entry.getValue())
                .collect(Collectors.toList());
        //第3，已开票
        result.add(new StatAuditDto(invoicesAmount, String.join("<br>", list3)));
        BigDecimal receivedAmount = tmp.stream()
                .filter(r -> r.getReceivedAmount() != null)
                .map(BizProject::getReceivedAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        Map<String, BigDecimal> map2 = tmp.stream()
                .filter(r -> r.getReceivedAmount() != null)
                .collect(Collectors.groupingBy(BizProjectResp::getDeptName,
                        Collectors.mapping(BizProjectResp::getReceivedAmount,
                                Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
        List<String> list2 = map2.entrySet().stream()
                .map(entry -> entry.getKey() + "：" + entry.getValue())
                .collect(Collectors.toList());
        //第2，回款额
        result.add(new StatAuditDto(receivedAmount, String.join("<br>", list2)));
        BigDecimal realIncome = tmp.stream()
                .filter(r -> r.getRealIncome() != null)
                .map(BizProject::getRealIncome)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        Map<String, BigDecimal> map1 = tmp.stream()
                .filter(r -> r.getRealIncome() != null)
                .collect(Collectors.groupingBy(BizProjectResp::getDeptName,
                        Collectors.mapping(BizProjectResp::getRealIncome,
                                Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
        List<String> list1 = map1.entrySet().stream()
                .map(entry -> entry.getKey() + "：" + entry.getValue())
                .collect(Collectors.toList());
        //第1，实际合同额
        result.add(new StatAuditDto(realIncome, String.join("<br>", list1)));
        return result;
    }
}
